﻿//////////////////////////////////////
//  ReportTitle
//////////////////////////////////////
// Create text on point with specified color
function ReportTitle(text, point, offset, opt_color) {  
  this.text_ = text;
  this.point_ = point;  
  this.offset_ = offset;
  this.color_ = opt_color || "#000000";
}

ReportTitle.prototype = new GOverlay();

// Creates the DIV representing this ReportTitle.
ReportTitle.prototype.initialize = function(map) {  
  // Create the DIV representing our ReportTitle  
  var div = document.createElement("div");  
    div.style.position = "absolute";
  // Our ReportTitle is flat against the map, so we add our selves to the  
  // MAP_PANE pane, which is at the same z-index as the map itself (i.e.,  
  // below the marker shadows)  
  map.getPane(G_MAP_MARKER_SHADOW_PANE).appendChild(div);  
  this.map_ = map;  
  this.div_ = div;
}

// Remove the main DIV from the map pane
ReportTitle.prototype.remove = function() {  
  this.div_.parentNode.removeChild(this.div_);
}

// Copy our data to a new ReportTitle
ReportTitle.prototype.copy = function() {  
  return new ReportTitle(this.text_, this.point_, this.color_, this.backgroundColor_, this.opacity_);
}

// Redraw the ReportTitle based on the current projection and zoom level
ReportTitle.prototype.redraw = function(force) {  
  // We only need to redraw if the coordinate system has changed
  if (!force) return;  
  this.div_.innerHTML = this.text_;
  // set pixel based coordinates from lat/lng
  var leftTop = this.map_.fromLatLngToDivPixel(this.point_);
  leftTop.x = leftTop.x + this.offset_.x;
  leftTop.y = leftTop.y + this.offset_.y;
  this.div_.style.color = this.color_;
  this.div_.style.left =  leftTop.x + "px";  
  this.div_.style.top = leftTop.y + "px";
  this.div_.noWrap = true;
  this.div_.style.width = this.text_.length + "em";
}


//////////////////////////////////////
//  ReportLoadingControl
//////////////////////////////////////
function ReportLoadingControl() {
  this.Left = 100;
  this.ImageSrc = '';
}

ReportLoadingControl.prototype = new GControl();

ReportLoadingControl.prototype.initialize = function(map) {
  var oDiv = document.createElement("div");
  oDiv.innerHTML = '<img src="' + this.ImageSrc + '" />';
  map.getContainer().appendChild(oDiv);
  return oDiv;
}

ReportLoadingControl.prototype.printable = function() {
  return true;
}

ReportLoadingControl.prototype.selectable = function() {
  return true;
}

ReportLoadingControl.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(this.Left, 7));
}


//////////////////////////////////////
// ReportCallbackErrorControl
//////////////////////////////////////
function ReportCallbackErrorControl() {
}

ReportCallbackErrorControl.prototype = new GControl();

ReportCallbackErrorControl.prototype.initialize = function(map) {
  this.innerDiv = document.createElement("div");
  this.innerDiv.style.bgColor = '#fff';
  this.innerDiv.style.display = 'none';
  map.getContainer().appendChild(this.innerDiv);
  return this.innerDiv;
}

ReportCallbackErrorControl.prototype.printable = function() {
  return true;
}

ReportCallbackErrorControl.prototype.selectable = function() {
  return true;
}

ReportCallbackErrorControl.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(5, 5));
}

ReportCallbackErrorControl.prototype.showError = function(sError) {
  this.innerDiv.style.display = 'block';
  this.innerDiv.innerHTML = sError;
}

//////////////////////////////////////
//  ReportCopyright
//////////////////////////////////////
function ReportCopyright() {
}

ReportCopyright.prototype = new GControl();

ReportCopyright.prototype.initialize = function(map) {
  var oDiv = document.createElement("div");
  oDiv.innerHTML = 'Created with <a href="http://www.codeplex.com/mapreport">Barbar MapReport API</a>';
  map.getContainer().appendChild(oDiv);
  return oDiv;
}

ReportCopyright.prototype.printable = function() {
  return true;
}

ReportCopyright.prototype.selectable = function() {
  return true;
}

ReportCopyright.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(300, 7));
}

//////////////////////////////////////
//  ReportGraph
//////////////////////////////////////

function GraphValue(height, color) {
  this.height_ = height;
  this.color_ = color;
}

// point - GPoint
// values - array of GraphValue elements
// opt_width - width of one single graph (optional)
function ReportGraph(point, values, opt_width) {
  this.point_ = point;
  this.values_ = values;
  this.width_ = opt_width || 5;
}

ReportGraph.prototype = new GOverlay();

ReportGraph.prototype.initialize = function(map) {
  this.divs_ = [];
  // Create the DIV for each single graph
  for (i = 0; i < this.values_.length; i++) {
    var div = document.createElement("div");
    div.style.position = "absolute";
    // Our MapTitle is flat against the map, so we add our selves to the  
    // MAP_PANE pane, which is at the same z-index as the map itself (i.e.,  
    // below the marker shadows)  
    map.getPane(G_MAP_MARKER_SHADOW_PANE).appendChild(div);
    this.divs_.push(div);
  }
  this.map_ = map;
}

// Remove the main DIV from the map pane
ReportGraph.prototype.remove = function() {
  for (i = 0; i < this.divs_.length; i++) {
    this.divs_[i].parentNode.removeChild(this.divs_[i]);
  }
}

// Copy our data to a new MapTitle
ReportGraph.prototype.copy = function() {
  return new MapTitle(this.point_, this.values_, this.width_, this.backgroundColor_, this.opacity_);
}

// Redraw the MapTitle based on the current projection and zoom level
ReportGraph.prototype.redraw = function(force) {
  // We only need to redraw if the coordinate system has changed  ]
  if (!force) return;
  var leftTop = this.map_.fromLatLngToDivPixel(this.point_);
  for (i = 0; i < this.values_.length; i++) {
    var div = this.divs_[i];
    var graph_value = this.values_[i];

    div.style.backgroundColor = graph_value.color_;
    div.style.left = (leftTop.x + this.width_ * i) + "px";
    div.style.top = (leftTop.y - graph_value.height_) + "px";
    div.style.width = this.width_ + "px";
    div.style.height = graph_value.height_ + "px";
  }
}

/////////////////////////////////////////////////////
//  GMap2 enhancments - enhancments have 'rpt' prefix
/////////////////////////////////////////////////////
GMap2.prototype.rptControls = new Array();
GMap2.prototype.rptLoadingControl = new ReportLoadingControl();
GMap2.prototype.rptCallbackErrorControl = new ReportCallbackErrorControl();
GMap2.prototype.rptServerCallbackData = new Array();
GMap2.prototype.rptIndicators = new Array();
GMap2.prototype.rptRegions = new Object();
GMap2.prototype.rptGeoLines = new Array();
GMap2.prototype.rptGeoArrows = new Array();

GMap2.prototype.rptInitialize = function() {
  this.addControl(new GMapTypeControl());
  this.addControl(new ReportCopyright());
  this.addControl(this.rptCallbackErrorControl);
}

GMap2.prototype.rptEnableEvents = function() {
  this.enableDragging();
  this.enableDoubleClickZoom();
  this.enableScrollWheelZoom();
  for (var i = 0; i < this.rptControls.length; i++) {
    this.addControl(this.rptControls[i]);
  }
}

GMap2.prototype.rptDisableEvents = function() {
  this.disableDragging();
  this.disableDoubleClickZoom();
  this.disableScrollWheelZoom();
  for (var i = 0; i < this.rptControls.length; i++) {
    this.removeControl(this.rptControls[i]);
  }
}

GMap2.prototype.rptSetServerCallbackData = function(oItem) {
  this.rptServerCallbackData.push(oItem);
}

GMap2.prototype.rptRegisterControl = function(oControl) {
  this.rptControls.push(oControl);
  this.addControl(oControl);
}

// Create icon from specified url on point
GMap2.prototype.rptCreateMapMarker = function(oMarker) {
  var oIcon = new GIcon();

  oIcon.image = oMarker.url;
  oIcon.shadow = oMarker.url;
  oIcon.iconSize = new GSize(oMarker.width, oMarker.height);
  oIcon.shadowSize = new GSize(oMarker.width, oMarker.height);
  oIcon.iconAnchor = new GPoint(oMarker.width / 2, oMarker.height / 2);
  oIcon.infoWindowAnchor = new GPoint(oMarker.width / 2, oMarker.height / 2);
  var oGoogleMarker = new GMarker(new GLatLng(oMarker.lat, oMarker.lng), oIcon);
  oGoogleMarker.hyperlink = oMarker.hyperlink;

  if (oMarker.description && oMarker.showBubbleOnMouseOver) {
    GEvent.addListener(oGoogleMarker, "mouseover", function() {
      oGoogleMarker.openInfoWindowHtml(oMarker.description);
    });
  }

  if (oMarker.hyperlink) {
    GEvent.addListener(oGoogleMarker, "click", function() {
      window.open(oMarker.hyperlink);
    });
  }

  if (oMarker.description && !oMarker.showBubbleOnMouseOver) {
    GEvent.addListener(oGoogleMarker, "click", function() {
      this.closeInfoWindow();
      oGoogleMarker.openInfoWindowHtml(oMarker.description);
    });
  }

  if (oMarker.title) {
    var oTitle = new ReportTitle(oMarker.title, new GLatLng(oMarker.lat, oMarker.lng), new GPoint(0, oMarker.height), oMarker.titlecolor);
    this.addOverlay(oTitle);
  }

  this.addOverlay(oGoogleMarker);
  return oGoogleMarker;
}

///////////////////////////////
// callback function handlers
///////////////////////////////
GMap2.prototype.rptHandleValueIndicators = function(aMarkers) {
  while (this.rptIndicators.length > 0) {
    this.removeOverlay(this.rptIndicators.pop());
  }

  for (var i = 0; i < aMarkers.length; i++) {
    var oServerObject = aMarkers[i];

    var oMarker = new Object();
    oMarker.url = oServerObject.url;
    oMarker.width = oServerObject.radius * 2;
    oMarker.height = oServerObject.radius * 2;
    oMarker.lat = oServerObject.point.t;
    oMarker.lng = oServerObject.point.g;
    oMarker.description = oServerObject.description;
    oMarker.showBubbleOnMouseOver = false;

    this.rptIndicators.push(this.rptCreateMapMarker(oMarker));
  }
}

GMap2.prototype.rptHandleRegionCallback = function(aRegions) {
  // optimalization - duplicate regions are ignored when callbacking
  for (var sKey in this.rptRegions) {
    if (aRegions[sKey])
      delete aRegions[sKey];
    else {
      this.removeOverlay(this.rptRegions[sKey]);
      delete this.rptRegions[sKey];
    }
  }

  var oMap = this;

  for (var sKey in aRegions) {
    var oRegion = aRegions[sKey];
    var oPolygon = GPolygon.fromEncoded(oRegion);

    if (oRegion.behavior) {
      oPolygon.rptBehavior = oRegion.behavior;
      switch (oRegion.behavior.type) {
        case 'PolygonBehaviorBubble':
          GEvent.addListener(oPolygon, "click", function(point) {
            oMap.openInfoWindow(point, this.rptBehavior.description);
          });
          break;
        case 'PolygonBehaviorRedirect':
          GEvent.addListener(oPolygon, "click", function(point) {
            window.open(this.rptBehavior.url);
          });
          break;
        default:
          throw 'Unknown behavior type.';
      }
    }

    this.rptRegions[sKey] = oPolygon;
    this.addOverlay(oPolygon);
  }
}

//////////////////////////////////////
// end of callback function handlers
//////////////////////////////////////


GMap2.prototype.rptServerCallback = function(oResponse) {
  for (var i = 0; i < oResponse.length; i++) {
    if (eval('this.' + oResponse[i].fnName)) {
      eval('this.' + oResponse[i].fnName + '(oResponse[i].arg)');
    } else {
      // TODO: handle error
    }
  }
}

GMap2.prototype.rptServerCallbackError = function(oRequest) {
  var sError = '';
  if (oRequest.responseText) {
    var iFirstIndex = oRequest.responseText.indexOf('<body');
    iFirstIndex = oRequest.responseText.indexOf('>', iFirstIndex) + 1;
    var iLastIndex = oRequest.responseText.indexOf('</body>');
    sError = oRequest.responseText.substring(iFirstIndex, iLastIndex);
  }
  this.rptCallbackErrorControl.showError(sError);
}

GMap2.prototype.rptServerCallbackParseError = function(sResponse) {
  debugger;
}

GMap2.prototype.rptTriggerMoveEnd = function() {
  GEvent.trigger(this, 'moveend');
}

GMap2.prototype.rptRegisterServerCallback = function(oCallback) {
  GEvent.addListener(this, 'moveend', function() {
    var oRequest = GXmlHttp.create();
    oRequest.open("POST", oCallback.callbackUrl, true);
    oRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    this.rptDisableEvents();
    this.addControl(this.rptLoadingControl);

    var oMap = this;

    oRequest.onreadystatechange = function() {
      if (oRequest.readyState == 4) {
        if (oRequest.status == 200) {
          if (oRequest.responseText) {
            var oResponse = null;
            try {
              oResponse = eval(oRequest.responseText);
            } catch (err) {
              oMap.rptServerCallbackParseError(oRequest.responseText);
            }
            if (oResponse) {
              oMap.rptServerCallback(oResponse);
            }
          }
        } else {
          oMap.rptServerCallbackError(oRequest);
        }
        oMap.removeControl(oMap.rptLoadingControl);
        oMap.rptEnableEvents();
      }
    }

    var oBound = this.getBounds();
    var sServerCallbackData = '';
    for (var i = 0; i < this.rptServerCallbackData.length; i++) {
      sServerCallbackData += '&key' + this.rptServerCallbackData[i].key + '=' + this.rptServerCallbackData[i].value;
    }
    oRequest.send(
          'callbackId=' + oCallback.callbackId +
          '&handlerUrl=' + escape(oCallback.handlerUrl) +
          '&zoom=' + this.getZoom() +
          '&swLat=' + escape(oBound.getSouthWest().lat()) +
          '&swLng=' + escape(oBound.getSouthWest().lng()) +
          '&neLat=' + escape(oBound.getNorthEast().lat()) +
          '&neLng=' + escape(oBound.getNorthEast().lng()) +
          sServerCallbackData);
  });
}

GMap2.prototype.rptAddGraph = function(oGraph) {
  var aGraphValues = [];
  for (var i = 0; i < oGraph.values.length; i++) {
    aGraphValues.push(new GraphValue(oGraph.values[i], oGraph.colors[i]));
  }

  var oPoint = new GLatLng(oGraph.lat, oGraph.lng);

  if (oGraph.title) {
    var oTitle = new ReportTitle(oGraph.title, oPoint, new GPoint(0, 2), oGraph.titleColor);
    this.addOverlay(oTitle);
  }

  this.addOverlay(new ReportGraph(oPoint, aGraphValues, oGraph.columnWidth));
}

GMap2.prototype.rptCreateArrow = function(oGeoLine) {
  var iZoom = this.getZoom();
  if (oGeoLine.arrows[iZoom].length > 0) {
    var oArrow = new GPolygon([
      new GLatLng(oGeoLine.arrows[iZoom][0].t, oGeoLine.arrows[iZoom][0].g),
      new GLatLng(oGeoLine.arrows[iZoom][1].t, oGeoLine.arrows[iZoom][1].g),
      new GLatLng(oGeoLine.arrows[iZoom][2].t, oGeoLine.arrows[iZoom][2].g),
      new GLatLng(oGeoLine.arrows[iZoom][0].t, oGeoLine.arrows[iZoom][0].g)
    ],
     oGeoLine.color,
     1,
     oGeoLine.opacity,
     oGeoLine.color,
     oGeoLine.opacity
    );
    this.addOverlay(oArrow);
    this.rptGeoArrows.push(oArrow);
  }
}

GMap2.prototype.rptAddLine = function(oGeoLine) {
  var oStartLatLng = new GLatLng(oGeoLine.startPoint.t, oGeoLine.startPoint.g);
  var oEndLatLng = new GLatLng(oGeoLine.endPoint.t, oGeoLine.endPoint.g);
  var oPolyline = new GPolyline([oStartLatLng, oEndLatLng], oGeoLine.color, oGeoLine.width, oGeoLine.opacity);

  if (this.rptGeoLines.length == 0) {
    var oMap = this;
    GEvent.addListener(this, "zoomend", function() {
      for (var i = 0; i < oMap.rptGeoArrows.length; i++)
        oMap.removeOverlay(oMap.rptGeoArrows[i]);

      oMap.rptGeoArrows = new Array();

      for (var i = 0; i < oMap.rptGeoLines.length; i++) {
        oMap.rptCreateArrow(oMap.rptGeoLines[i]);
      }
    });
  }

  this.rptGeoLines.push(oGeoLine);
  this.addOverlay(oPolyline);
  this.rptCreateArrow(oGeoLine);
}


